package hypeerweb;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;


public abstract class BroadcastVisitor implements Visitor
{
    private class BroadcastSender extends SendVisitor
    {

        protected void targetOperation(Node node, Parameters parameters)
        {
            node.accept((Visitor)parameters.get(INNER_VISIT_KEY), (Parameters)parameters.get(INNER_PARAM_KEY));
        }

    }
    boolean launched = false;
    protected static final String STARTED_KEY = "__started__";
    protected static final String INNER_VISIT_KEY = "__visitor__";
    protected static final String INNER_PARAM_KEY = "__parameters__";
    
    public BroadcastVisitor() 
    {
        
    }
    public static Parameters createInitialParameters()
    {
        Parameters parameter = new Parameters();
        return parameter;        
    } 
    public void visit(Node node, Parameters parameters)
    {
        assert(node != Node.NULL_NODE);
        assert(node != null);
        assert(parameters != null);
        if(launched == false)
        {
            launched = true;
            BroadcastSender sender = new BroadcastSender();
            Parameters para = sender.createInitialParameters(0);
            para.set(INNER_PARAM_KEY, parameters);
            para.set(INNER_VISIT_KEY, this);
            node.accept(sender, para);
        }
        else
        {
            List<Integer> broadcast_points = getBroadcastPoints(node.getWebId());
            operation(node,parameters);
            for(Node n: node.getNeighbors())
            {
                if(broadcast_points.contains(n.getWebId().getValue()))
                {
                    n.accept(this, parameters);
                }
            }
        }
    }
    protected abstract void operation(Node node, Parameters parameters);
    
    public List<Integer> getBroadcastPoints(WebId curNode)
    {
        List<Integer> ans = new LinkedList<Integer>();
        int start = 1;
        for(int i = 0; i < curNode.getHeight(); i++)
        {
            int cur = curNode.getValue() ^ start;
            if(cur < curNode.getValue())
                break;
            ans.add(cur);
            start = start << 1;
        }
        return ans;
    }
    
}